package util;

import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map.Entry;

/**
 * Handles an object with its fields
 * 
 * @author tanjian
 * 
 */
public class ReflectUtil {
	private String[] names;
	private Object[] values;
	private String objName;

	/**
	 * @param names
	 *            the names to set
	 */
	public void setNames(String[] names) {
		this.names = names;
	}

	/**
	 * @return the names
	 */
	public String[] getNames() {
		return names;
	}

	public Object[] getValues() {
		return values;
	}

	public void setValues(Object[] values) {
		this.values = values;
	}

	/**
	 * Transform an object to a reflectUtil object
	 * 
	 * @param o
	 * @return
	 * @throws Exception
	 */
	public ReflectUtil getReflectClass(Object o) throws Exception {
		ReflectUtil rc = new ReflectUtil();
		Class<? extends Object> clazz = o.getClass();
		this.objName = clazz.getName();
		Field[] f = clazz.getDeclaredFields();
		rc.setNames(field2Name(f));
		rc.setValues(field2Value(f, o));
		return rc;
	}

	/**
	 * Print the name and values
	 * 
	 * @param name
	 * @param value
	 */
	public void showNameAndValue(String[] name, Object[] value) {
		for (int i = 0; i < name.length; i++) {
			System.out.println("--" + i + "--");
			System.out.println("name:" + name[i]);
			System.out.println("Value:" + value[i]);
			System.out.println("--     --");
		}
	}

	/**
	 * Get all the field names
	 * 
	 * @param f
	 * @return
	 */
	public static String[] field2Name(Field[] f) {
		String[] name = new String[f.length];
		for (int i = 0; i < f.length; i++) {
			name[i] = f[i].getName();
		}
		return name;
	}

	/**
	 * Get all the field values from an object
	 */

	public static Object[] field2Value(Field[] fields, Object o)
			throws Exception {
		Object[] values = new Object[fields.length];
		Class<? extends Object> classType = o.getClass();
		for (int i = 0; i < fields.length; i++) {
			String fieldName = fields[i].getName();
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getMethodName = "get" + firstLetter + fieldName.substring(1);
			Method getMethod = classType.getMethod(getMethodName,
					new Class[] {});
			values[i] = getMethod.invoke(o, new Object[] {});
		}
		return values;
	}

	public static HashMap<String, Object> getNameValueEntry(Object o)
			throws Exception {
		HashMap<String, Object> hm = new HashMap<String, Object>();
		Class<? extends Object> clazz = o.getClass();
		Field[] fields = clazz.getDeclaredFields();
		Class<? extends Object> classType = o.getClass();
		for (int i = 0; i < fields.length; i++) {
			String fieldName = fields[i].getName();
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getMethodName = "get" + firstLetter + fieldName.substring(1);
			Method getMethod = classType.getMethod(getMethodName,
					new Class[] {});
			hm.put(fieldName, getMethod.invoke(o, new Object[] {}));
		}
		return hm;
	}

	/**
	 * Get all the fields from an object
	 * 
	 * @param o
	 * @return
	 */
	public static Field[] getFields(Object o) {
		Class<? extends Object> clazz = o.getClass();
		return clazz.getDeclaredFields();
	}

	/**
	 * Get a field by its name
	 * 
	 * @param name
	 * @param o
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 */
	public static Field getFieldByName(String name, Object o)
			throws SecurityException, NoSuchFieldException {
		Class<? extends Object> clazz = o.getClass();
		return clazz.getDeclaredField(name);
	}

	/**
	 * Get object full name with packages.
	 * 
	 * @param o
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 */
	public static String getName(Object o) throws SecurityException,
			NoSuchFieldException {
		Class<? extends Object> clazz = o.getClass();
		return clazz.getName();
	}

	/**
	 * Get object simple name
	 * 
	 * @param o
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 */
	public static String getSimpleName(Object o) throws SecurityException,
			NoSuchFieldException {
		Class<? extends Object> clazz = o.getClass();
		return clazz.getSimpleName();
	}

	/**
	 * Set the named attibutes with values.
	 * 
	 * @param name
	 * @param value
	 * @param o
	 * @return
	 * @throws Exception
	 */
	public static Object setObjectValues(String[] name, Object[] value, Object o)
			throws Exception {
		if (name.length != value.length) {
			throw new Exception("Name dismatchs to value");
		}
		Field[] f = getFields(o);
		for (int i = 0; i < name.length; i++) {
			for (int j = 0; j < f.length; j++) {
				if (f[j].getName().equals(name[i])) {
					f[j].setAccessible(true);
					f[j].set(o, value[i]);
				}
			}
		}
		return o;
	}

	/**
	 * Set the attributes of an object with entries of a HashMap
	 * 
	 * @param <E>
	 * 
	 * @param hm
	 * @param o
	 * @return
	 * @throws Exception
	 */
	public static <E> E setObjectValues(HashMap<String, Object> hm, E e)
			throws Exception {
		Field[] fields = getFields(e);
		for (Entry<?, ?> entry : hm.entrySet()) {
			for (Field field : fields) {
				if (field.getName().equals(entry.getKey())) {
					field.setAccessible(true);
					field.set(e, entry.getValue());
				}
			}
		}
		return e;
	}

	public static void main(String[] args) throws Exception {
		// ApplyForm af = new ApplyForm();
		// af.setDescription("123");
		// af.setMaterialId("456");
		// af.setStatusId("333");
		// af.setUserId("4444");
		// // User usr = new User();
		// // usr.setGroupId("111");
		// // usr.setName("222");
		// // usr.setPassword("333");
		// // usr.setRoleId("444");
		// // usr.setUserId("555");
		// ReflectClass rc = new ReflectClass().getReflectClass(af);
		// rc.showNameAndValue(rc.getNames(), rc.getValues());

	}

	/**
	 * @param objName
	 *            the objName to set
	 */
	public void setObjName(String objName) {
		this.objName = objName;
	}

	/**
	 * @return the objName
	 */
	public String getObjName() {
		return objName;
	}
}
